'''
NurbsCad
Archivo camara utilizado principalmente por el escena.py 
Autor: Gustavo Enrique Bellino
Contacto: gushbellino@gmail.com
Fecha: Junio de 2009
Descripcion: archivo con una clase llamada Camara que se utiliza principalmente para mover la camara y punto de vista del observador
del area de trabajo.
Licencia: GNU Public License version 2
'''

#Importa las librerias necesarias
from __future__ import division
import os, sys, math
#Se agrega al path la carpeta ../lib
modulesdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib'))
sys.path.insert(0, modulesdir)
#Se agrega al path la carpeta ../
modulesdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))
sys.path.insert(0, modulesdir)
#librerias de un nivel superior
from lib.euclid import Vector3
from library import Library

#Intenta cargar OpenGL, si no lo logra lanza un error y termina
try:
  from OpenGL.GLUT import *
  from OpenGL.GL import *
  from OpenGL.GLU import *
except:
  print 'ERROR: PyOpenGL is not installed properly.'
  sys.exit()

class Camara(Library):
    def __init__(self, eyes, lookAt, up, escena):
        ''' Inicializa una camara para una aplicacion pyopengl. 
        parametros: 3 parametros tipo Vector3
        eyes: desde donde se observa
        lookAt: hacia donde se observa
        up: indicador de posicion hacia arriba de la camara'''
        
        self.escena = escena
        
        self.eyes = eyes
        self.lookAt = lookAt
        self.up = up
        
        self.clickedX = 0
        self.clickedY = 0
        
        self.moveCamera = True
        self.panActive = False
        self.ligthsActive = False
        
        self.autoEliminate = False
        self.type = 'Camara'
   
    def rotateEyes(self, ang, eje):
        '''ang: angulos a rotar en radianes, eje: eje sobre el cual se rota, tipo Vector3'''
        self.eyes = self.eyes.rotate(ang, eje)
        #tambien se rota el valor de up para no tener ambiguedades
        self.up = self.up.rotate(ang, eje)

    def rotateLookAt(self, ang, eje):
        '''ang: angulos a rotar en radianes, eje: eje sobre el cual se rota, tipo Vector3'''
        self.lookAt = self.lookAt.rotate(ang, eje)

    def rotateUp(self, ang, eje):
        '''ang: angulos a rotar en radianes, eje: eje sobre el cual se rota, tipo Vector3'''
        self.up = self.up.rotate(ang, eje)

    def zoom(self, speed, tolerance = 6):
        ''' Translada el vector del ojo (eyes) siempre y cuando la distancia entre el vector eyes y el lookAt sea mayor que una tolerancia
        Parametros: zoom(self, speed, tolerance = 6)'''
        #vector desplazamiento
        vectDesp = self.lookAt - self.eyes
        
        #si es zoomIn controla la tolerancia sino no
        if(speed < 0 or (vectDesp.module() > tolerance)):
            vectDesp *= speed #velocidad de desplazamiento
            self.eyes += vectDesp
            self.regen()
            return True
        else:
            return False

    def zoomIn(self, speed = 0.1):
        self.zoom(speed)
        self.escena.queue_draw()
        return

    def zoomOut(self, speed = 0.1):
        self.zoom(-speed)
        self.escena.queue_draw()
        return

    def pan(self, vectDesp):
        self.eyes += vectDesp
        self.lookAt += vectDesp
        return

    def activePan(self, is_active=None):
        if is_active == None:
            self.panActive = not self.panActive
        else:
            self.panActive = is_active
            self.moveCamera = not is_active

    def getEyes(self):
        return self.eyes
        
    def getLookAt(self):
        return self.lookAt
        
    def getUp(self):
        return self.up

    #OpenGL Section

    def initialize(self):
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(40.0, 0.79, 0.1, 3000.0)
        
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(
                  self.eyes.x, self.eyes.y, self.eyes.z, 
                  self.lookAt.x, self.lookAt.y, self.lookAt.z,
                  self.up.x, self.up.y, self.up.z)

    def regen(self):
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        gluLookAt(
                  self.eyes.x, self.eyes.y, self.eyes.z, 
                  self.lookAt.x, self.lookAt.y, self.lookAt.z,
                  self.up.x, self.up.y, self.up.z)

    #CallBacks
    def Mouse(self, button, x, y):
        if(button==1):
            self.moveCamera = True
            self.clickedX = x
            self.clickedY = y
        else:
            self.moveCamera = False
    
    def Motion(self, x, y, width, heigth,  plano):
        if(self.moveCamera):
            #segun la posicion en y  se evalua la rotacion del up
            val1 = (y - heigth / 2.0)**2/(heigth/2.0)**2
            val2 = -val1 + 1
            if(y>heigth/2):
                val1 *= -1
            
            if(self.clickedX!=0):
                difX = self.clickedX - x
                angX = math.pi * difX / width
            else:
                angX = 0

            if(self.clickedY!=0):
                difY = y - self.clickedY
                angY = math.pi * difY / heigth
            else:
                angY = 0
                
            self.clickedX = x
            self.clickedY = y
            
            #rotacion de la camara
            ejeTmp = (self.eyes-self.lookAt).cross(self.up)
            self.rotateEyes(angY, ejeTmp)
            self.rotateUp(-angX*val1, self.eyes)
            self.rotateEyes(angX*val2, self.up)
            self.regen()
            
        if(self.panActive): #si esta activado el movimiento pam
            if(self.clickedX!=0):
                difX = self.clickedX - x
            else:
                difX = 0

            if(self.clickedY!=0):
                difY = y - self.clickedY
            else:
                difY = 0
                
            self.clickedX = x
            self.clickedY = y
            
            vectDespVert = self.up * difY * 0.01
            vectDespHor = (self.up.cross(self.lookAt - self.eyes)).normalize()
            vectDespHor *= difX* -0.01
            self.pan(vectDespVert + vectDespHor)
            self.moveCamera = False
            self.regen()
        return 0

    def Scroll(self, direction, x, y):
        if(direction):
            self.zoomIn(0.05)
        else:
            self.zoomOut(0.04)
        return

    def ScrollPaned(self, direction, x, y):
        if(direction):
            pto = self.convertTo3D(x, y)
            proyOfUp = self.up.proyection(pto)
            vectDespVert = self.up * proyOfUp
            
            vectDespHor = (self.up.cross(self.lookAt - self.eyes)).normalize()
            proyHor = vectDespHor.proyection(pto)
            vectDespHor *= proyHor
            vect = ( vectDespVert.normalize() + vectDespHor.normalize() ) * 0.25
            self.pan( vect )

    def atributesToEdit(self):
        self.atributes = {'Eyes': (self.eyes, lambda widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3: self.setEyes(widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3)), 
               'Look At': (self.lookAt,lambda widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3: self.setLookAt(widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3)), 
               'Up': (self.up, lambda widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3: self.setUp(widget,spinbutton_widget1,spinbutton_widget2,spinbutton_widget3))
        }
        return self.atributes
    
    def setEyes(self,widget, spinbutton_widget1,spinbutton_widget2,spinbutton_widget3):
        valorX = spinbutton_widget1.get_value()
        valorY = spinbutton_widget2.get_value()
        valorZ = spinbutton_widget3.get_value()
        valorV=Vector3(valorX,valorY,valorZ);
        self.eyes = valorV
        self.escena.queue_draw()
        return True

    def setLookAt(self,widget, spinbutton_widget1,spinbutton_widget2,spinbutton_widget3):
        valorX = spinbutton_widget1.get_value()
        valorY = spinbutton_widget2.get_value()
        valorZ = spinbutton_widget3.get_value()
        valorV=Vector3(valorX,valorY,valorZ);
        self.lookAt = valorV
        self.escena.queue_draw()
        return True

    def setUp(self,widget, spinbutton_widget1,spinbutton_widget2,spinbutton_widget3):
        valorX = spinbutton_widget1.get_value()
        valorY = spinbutton_widget2.get_value()
        valorZ = spinbutton_widget3.get_value()
        valorV=Vector3(valorX,valorY,valorZ);
        self.up = valorV
        self.escena.queue_draw()
        return True

    def actionsToDo(self):
        
        if(self.ligthsActive):
            ligthsString = 'Not Active LIGTHS'
        else:
            ligthsString = 'Active LIGTHS'
        
        self.actions = {
        '1-Camera Active': lambda button_widget: self.activePan(False), 
        '2-PAN Active': lambda button_widget: self.activePan(True), 
        '3-Zoom In': lambda button_widget: self.zoomIn(),
        '4-Zoom out': lambda button_widget: self.zoomOut(),
        '5-X-Y':    lambda button_widget: self.view_x_y(20), 
        '6-X-Z': lambda button_widget: self.view_x_z(20), 
        '7-Y-Z': lambda button_widget: self.view_y_z(20), 
        '8-Ligth': lambda button_widget:self.activeLigths()
                            }
        return self.actions.keys()
    
    def activeLigths(self):
        self.ligthsActive = not self.ligthsActive
        self.regen()
        print 'ligthsActive', self.ligthsActive
    
    def probarOptimizacion(self):
        import time
        veces = 10000
        inicia = time.time()
        angY = 0.01
        ejeTmp = (self.eyes-self.lookAt).cross(self.up)
        self.rotateEyes(angY, ejeTmp)
        ahora = time.time()
    
    def functionReturn(self, widget, event):
        indice = widget.get_label()
        return self.actions[indice]()

    def functionReturnToEdit(self, indice, value):
        return self.atributes[indice][1](value)

    def view_x_y(self, dist = 15):
        #vista del plano x-y
        self.lookAt = Vector3(0, 0, 0)
        self.eyes = Vector3(0, 0, dist)
        self.up = Vector3(0, 1, 0)
        self.escena.queue_draw()  

    def view_x_z(self, dist = 15):
        #vista del plano x-y
        self.lookAt = Vector3(0, 0, 0)
        self.eyes = Vector3(0, dist, 0)
        self.up = Vector3(0, 0, 1)
        self.escena.queue_draw()

    def view_y_z(self, dist = 15):
        #vista del plano x-y
        self.lookAt = Vector3(0, 0, 0)
        self.eyes = Vector3(dist, 0, 0)
        self.up = Vector3(0, 1, 0)
        self.escena.queue_draw()

def main():
    a = vector3P.Vector3b()
    a.set(1,0,0)


    b = vector3P.Vector3b()
    b.set(0,0,1)

    ang = math.pi/4.0
    c = a.rotate(ang,b)
    
    print c. __repr__()

if __name__ == '__main__': 
    main()
